home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 090 / vol7n5.arc / ASPRN.ASM next >
Encoding:
Assembly Source File  |  1988-03-15  |  52.4 KB  |  1,776 lines

  1.      TITLE    ASPRN - Printer Macro Expander
  2.     PAGE    60,132
  3. ;======================================================================
  4. ;  ASPRN - A printer macro expansion utility.  A TSR that watches INT 17
  5. ;  and looks for an escape sequence of the form [char]x where x={A-Z} and
  6. ;  expands it to a setup string.  Clones itself to include changes in
  7. ;  the COM file.  Different macro characters act like different programs.
  8. ;
  9. ;    Usage: ASPRN [ /U | /S ][ /Mx | /Cnnn ]
  10. ;
  11. ;  9/12/87    .001    Complete memory management routines. (469)
  12. ;        .002    Add EXPAND. (674)
  13. ;  10/9/87    .003    Clean-up.  Start Editor (1030)
  14. ;          .004    Restructure all code (1026)
  15. ;        .005    Structure EDITOR proc (1200)
  16. ;        .006    Add display and pointer routines
  17. ;  10/10/87    .007    String edit functions/key reading
  18. ;  10/11/87    .008    Extract right/left cursor (1766)
  19. ;  11/6/87    .009    Add HOME/END. Fix TTY. (2109)
  20. ;  11/7/87    .010    Cleanup. Enhance error messages (2197)
  21. ;  11/18/87    .011    Add labels, adjust columns. (2232)
  22. ;  11/22/87    .012    Add panic switch, change name (2315)
  23. ;----------------------------------------------------------------------
  24.  
  25. CSEG    SEGMENT PARA PUBLIC 'CODE'
  26.     ASSUME    CS:CSEG,DS:NOTHING,ES:NOTHING,SS:NOTHING
  27.  
  28. ;----------------------------------------------------------------------
  29. ;  Some common equates.
  30. ;----------------------------------------------------------------------
  31.  
  32. CR        EQU    13            ;Common equates
  33. LF        EQU    10
  34.  
  35. INS        EQU    52H            ;Extended ASCII values
  36. DEL        EQU    53H
  37. F7KEY        EQU    41H
  38. HOME        EQU    47H
  39. ENDKEY        EQU    4FH
  40. PGUP        EQU    49H
  41. PGDN        EQU    51H
  42. RARROW        EQU    4DH
  43. LARROW        EQU    4BH
  44. UARROW        EQU    48H
  45. DARROW        EQU    50H
  46. BS        EQU    0E08H            ;Scan/Ascii code
  47.  
  48. U_SW        EQU    1            ;Request to Uninstall
  49. S_SW        EQU    2            ;Do a Setup
  50. M_SW        EQU    4            ;Change Escape char
  51. ERR_SW        EQU    0FFH            ;General error
  52.  
  53. ;----------------------------------------------------------------------
  54. ;  Start of code.
  55. ;----------------------------------------------------------------------
  56.         ORG    100H            ;Starting offset for COM
  57. ENTPT:        JMP    INITIALIZE        ;Skip over resident code
  58.  
  59. ESC_CHAR    DB    "~"            ;Escape char used as part
  60.                         ; of program signature
  61.  
  62. COPYRIGHT    DB    "ASPRN 1.0 (c) 1988 Ziff Communications Co.",CR,LF
  63.         DB    "PC Magazine ",254," Robert L. Hummel",CR,LF,"$",26
  64.  
  65. OLD_INT17    DW    0,0            ;Store old vector here
  66.  
  67. ;----------------------------------------------------------------------
  68. ;  A Far Pointer is kept to point to strings so they can be found anywhere
  69. ;  in memory.  The length of strings is here as well.  These are updated
  70. ;  when a modified copy is written to disk.
  71. ;----------------------------------------------------------------------
  72.  
  73. STRING_LOC    DW    OFFSET STRINGS,0
  74. STRING_LEN    DW    OFFSET STRING_END - OFFSET STRINGS
  75.  
  76. ;=======================================================================
  77. ;  MACRO EXPANDER - This portion stays resident and is loaded only once.
  78. ;  Each time a character is output to the printer, check to see if it is
  79. ;  our escape char.  If so, don't send it.  The next char will indicate
  80. ;  which string to send in it's place.  If two escape chars are sent in
  81. ;  a row, print one copy of the escape char.
  82. ;----------------------------------------------------------------------
  83. ESC_FLAG    DB    0            ;=1 if last was Esc-char
  84. PANIC_FLAG    DB    0            ;Non-zero in emergencies
  85.  
  86. INT17        PROC    FAR
  87.     ASSUME    CS:CSEG,DS:NOTHING,ES:NOTHING,SS:NOTHING
  88.  
  89.         CMP    CS:PANIC_FLAG,0        ;If panic flag
  90.         JNE    INT17_0            ; do nothing
  91.  
  92.         STI                ;Allow interrupts
  93.         OR    AH,AH            ;If print char function
  94.         JZ    INT17_1            ; check for ESC_CHAR
  95. INT17_0:
  96.         CLI                ;Disable interrupts
  97.         JMP    DWORD PTR CS:OLD_INT17    ;Else, continue
  98. INT17_1:
  99.         CMP    CS:ESC_FLAG,0        ;Was last char esc?
  100.         JNE    INT17_2            ;Yes, go expand
  101.  
  102.         CMP    AL,CS:ESC_CHAR        ;Is this an esc_char
  103.         JNE    INT17_0            ;No, just print it
  104.  
  105.         INC    CS:ESC_FLAG        ; else, set latch
  106. INT17_1A:
  107.         MOV    AH,2            ;Get status instead
  108.         JMP    INT17_0            ; from original interrupt
  109. INT17_2:
  110.         MOV    CS:ESC_FLAG,0        ;Clear latch
  111.         CMP    AL,CS:ESC_CHAR        ;If second esc_char
  112.         JE    INT17_0            ; output single char
  113.  
  114.         OR    AL,20H            ;Make lower case
  115.         SUB    AL,"a"            ;Convert to 0-25
  116.         CMP    AL,25            ;Must be in range
  117.         JA    INT17_1A        ; else ignore
  118.  
  119.         CALL    EXPAND            ;Exand the macro
  120.         JMP    INT17_1A        ;Exit with status call
  121.  
  122. INT17        ENDP
  123.  
  124.  
  125. ;======================================================================
  126. ;  Expand the macro for this string combination.  Enter with AL = string
  127. ;  number (must be 0-25).  DX = printer number (from original int).
  128. ;----------------------------------------------------------------------
  129. EXPAND        PROC    NEAR
  130.     ASSUME    CS:CSEG,DS:NOTHING,ES:NOTHING,SS:NOTHING
  131.  
  132.         PUSH    DS            ;Saved used registers
  133.         PUSH    SI
  134.         PUSH    CX
  135.  
  136.         LDS    SI,DWORD PTR STRING_LOC    ;Point DS:SI to strings
  137.         MOV    CL,AL            ;Each macro occupies two
  138.         ADD    CL,CL            ; strings, so double
  139.         INC    CL            ; and add one
  140. EXP_0:
  141.         OR    CL,CL            ;If at selected string
  142.         JZ    EXP_2            ; copy it to printer
  143.         DEC    CL            ;Adjust counter
  144. EXP_1:
  145.         LODSB                ;Find the string end
  146.         OR    AL,AL            ;If not terminating zero
  147.         JNZ    EXP_1            ; continue to read string
  148.         JMP    EXP_0            ;Else find next string
  149. EXP_2:
  150.         LODSB                ;Get a char
  151.         OR    AL,AL            ;At end of string?
  152.         JZ    EXP_3            ;Yes, exit
  153.         PUSHF                ;No, simulate INT 17h
  154.         XOR    AH,AH            ; print the character
  155.         CALL    DWORD PTR CS:OLD_INT17    ; through old int
  156.         CMP    AH,10h            ;Check return status
  157.         JE    EXP_2            ; continue if no error
  158. EXP_3:
  159.         POP    CX            ;Restore used registers
  160.         POP    SI
  161.         POP    DS
  162.         RET                ;And return
  163.  
  164. EXPAND        ENDP
  165.  
  166. ;----------------------------------------------------------------------
  167. ;  This is the smallest amount of the program that can remain in memory
  168. ;  and still function.
  169. ;----------------------------------------------------------------------
  170. MINIMUM        EQU    $
  171.  
  172.  
  173. ;======================================================================
  174. ;  SHRIVEL is really the part of INITIALIZE that makes sure we use as
  175. ;  little memory as possible by relocating the strings downward.
  176. ;----------------------------------------------------------------------
  177. SHRIVEL        PROC    NEAR
  178.     ASSUME    CS:CSEG, DS:CSEG, ES:NOTHING, SS:NOTHING
  179.  
  180.         CLD                ;String moves forward
  181.         MOV    SI,OFFSET STRINGS    ;Source of strings
  182.         MOV    DI,OFFSET CUTOFF    ;Destination
  183.         MOV    CX,STRING_LEN        ;Number bytes to move
  184.  
  185.         MOV    STRING_LOC[2],ES    ;New segment of strings
  186.         MOV    STRING_LOC[0],DI    ;New offset
  187.  
  188.         MOV    DX,CX            ;Save length of strings
  189.         ADD    DX,DI            ; add to program length
  190.  
  191.         REP    MOVSB            ;Move DS:SI to ES:DI
  192.  
  193.         ADD    DX,15            ;Round to nearest paragraph
  194.         MOV    CL,4            ;Convert to paras
  195.         SHR    DX,CL            ; by dividing
  196.         MOV    AX,3100H        ;Terminate & stay resident
  197.         INT    21H            ; thru DOS
  198.  
  199. SHRIVEL        ENDP
  200.  
  201. ;----------------------------------------------------------------------
  202. ;  When terminating for the first time, the SHRIVEL proc must be left
  203. ;  resident to do the dirty work.  Everything after CUTOFF is discarded
  204. ;  or written over by the strings.
  205. ;----------------------------------------------------------------------
  206. CUTOFF        EQU    $
  207.  
  208.  
  209. ;======================================================================
  210. ;  The INITIALIZE procedure performs most of the work.  It interprets
  211. ;  the command line switches, checks for previous copies, and does all
  212. ;  the memory management.  Entry is via JMP.
  213. ;----------------------------------------------------------------------
  214. NOT_RES$    DB    "Not Resident$"
  215. CANT_GO$    DB    "Cannot Uninstall$"
  216. SYNTAX$        DB    "Usage:  ASPRN [ /U | /S ][ /Mx | /Cnnn ]$"
  217.  
  218. INITIALIZE    PROC    NEAR
  219.         ASSUME    CS:CSEG, DS:CSEG, ES:CSEG, SS:CSEG
  220.  
  221. ;----------------------------------------------------------------------
  222. ;  Set up a local stack at the end of the program.
  223. ;----------------------------------------------------------------------
  224.         CLI                ;Disable interrupts
  225.         MOV    SP,OFFSET STACK_TOP    ;SS:SP points to stack
  226.         STI                ;Allow interrupts
  227.  
  228. ;----------------------------------------------------------------------
  229. ;  Display the copyright notice.
  230. ;----------------------------------------------------------------------
  231.         MOV    DX,OFFSET COPYRIGHT    ;Say who we are
  232.         MOV    AH,9            ;Display string function
  233.         INT    21H            ; Thru DOS
  234.  
  235. ;----------------------------------------------------------------------
  236. ;  Release the copy of the environment allocated to this program.  The
  237. ;  segment address of the env block is located at offset 2Ch in the PSP.
  238. ;----------------------------------------------------------------------
  239.         PUSH    ES            ;Save register
  240.  
  241.         MOV    BX,WORD PTR DS:[2CH]    ;Get environment segment
  242.         MOV    ES,BX            ; in ES
  243.     ASSUME    ES:NOTHING
  244.         MOV    AH,49H            ;Free allocated memory
  245.         INT    21H            ; Thru DOS
  246.  
  247.         POP    ES            ;Restore register
  248.     ASSUME    ES:CSEG
  249.  
  250. ;----------------------------------------------------------------------
  251. ;  The CMD_LINE procedure looks for switches on the command tail and
  252. ;  returns them bit-packed in AH.
  253. ;
  254. ;  /S (Setup) will invoke the editor and allow changes to be made to the
  255. ;    loaded copy and written out to disk.  No changes are made to the
  256. ;    resident copy if one exists.
  257. ;  /Mx (Macro char) will substitute the char x for the default escape
  258. ;    char.  If the /S parameter is specified, the char will be changed
  259. ;    in the loaded copy and written back to disk.  Otherwise, the char
  260. ;    is used to determine residency and operation characteristics.
  261. ;  /Cnnn (escape Char) Same as /E, but allows any char from 001-255 to
  262. ;    be specified as a decimal number.
  263. ;  /U (Uninstall) Will flush the resident copy if possible.
  264. ;    Otherwise, no action.  Other switches are ignored.
  265. ;----------------------------------------------------------------------
  266.         CALL    CMD_LINE        ;Get switches in AH
  267.         JNC    INIT_1            ;If no carry, no error
  268.  
  269.         MOV    DX,OFFSET SYNTAX$    ;Show correct syntax
  270. INIT_0:
  271.         MOV    AH,9            ;Display string fn
  272.         INT    21H            ; Thru DOS
  273.  
  274.         MOV    AX,4C01h        ;Terminate with error
  275.         INT    21H            ; Thru DOS
  276. INIT_1:
  277. ;----------------------------------------------------------------------
  278. ;  Process the flags.
  279. ;----------------------------------------------------------------------
  280.         TEST    AH,U_SW            ;Request to unload?
  281.         JZ    INIT_2            ;No, check next switch
  282.  
  283.         CALL    UNLOAD            ;Unload if possible
  284.         JC    INIT_0            ;Carry set if error
  285.  
  286.         MOV    AX,4C00H        ;Terminate okay
  287.         INT    21H            ; Thru DOS
  288. INIT_2:
  289.         TEST    AH,S_SW            ;Setup switch on?
  290.         JZ    INIT_3            ;No, check next option
  291.         JMP    SETUP            ;Yes, invoke the editor
  292. INIT_3:
  293.         CALL    FIND_RES        ;Look for resident copy
  294.     ASSUME    ES:NOTHING            ; ES may have changed
  295.  
  296.         JC    LOAD            ;No copy found - try load
  297.         JMP    REPLACE            ; else, replace
  298.  
  299. INITIALIZE    ENDP
  300.  
  301.  
  302. ;======================================================================
  303. ;  This procedure will cause the load copy of the program to become
  304. ;  resident.  The new copy will try to locate the strings as low in
  305. ;  memory as possible.  Hook the interrupt vectors, load the strings,
  306. ;  and TSR.  Entry via JMP.
  307. ;----------------------------------------------------------------------
  308. LOAD        PROC    NEAR
  309.     ASSUME    CS:CSEG, DS:CSEG, ES:CSEG
  310.  
  311.         PUSH    ES            ;Preserve register
  312.     ASSUME    ES:NOTHING            ; Changed by next call
  313.  
  314.         MOV     AX,3517H        ;Get BIOS printer INT
  315.         INT    21H            ;Result in ES:BX
  316.  
  317.         MOV    OLD_INT17[0],BX        ;Save old vector
  318.         MOV    OLD_INT17[2],ES        ; in local storage
  319.  
  320.         POP    ES            ;Restore register
  321.     ASSUME    ES:CSEG
  322.  
  323.         MOV    AX,2517H        ;Set new interrupt
  324.         MOV    DX,OFFSET INT17        ; to us at DS:DX
  325.         INT    21H            ; Thru DOS
  326.  
  327. ;----------------------------------------------------------------------
  328. ;  As loaded, ASPRN owns all memory from its PSP to the end of memory.
  329. ;  Thus the only memory an allocation call will find will be below us.
  330. ;  Try to find a low memory block to contain the strings.  If success,
  331. ;  AX contains segment of allocated block.  If no room is found, discard
  332. ;  excess code and relocate strings downward.
  333. ;----------------------------------------------------------------------
  334.         CALL    FIND_LOW        ;Look for lower block
  335.         JNC    LOAD_1            ;No Carry if found
  336.  
  337.         JMP    SHRIVEL            ;No room in low mem
  338.  
  339. ;----------------------------------------------------------------------
  340. ;  A chunk of memory of suitable size was found below this program at
  341. ;  segment in AX. Relocate the strings to the new area.  DS:SI to AX:DI
  342. ;  Then TSR,leaving only the macro expander resident in this segment.
  343. ;----------------------------------------------------------------------
  344. LOAD_1:
  345.         CALL    MOVE_STRINGS        ;Move the strings
  346.  
  347.         MOV    DX,(OFFSET MINIMUM - OFFSET CSEG + 15) SHR 4
  348.         MOV    AX,3100H        ;Keep process resident
  349.         INT    21H            ; Thru DOS
  350.  
  351. LOAD        ENDP
  352.  
  353.  
  354. ;======================================================================
  355. ;  Read the command line.  Set flags in AH to indicate which switches
  356. ;  were included.  Note: the /M /C flags are eaten internally and are
  357. ;  set for ease of later modification.
  358. ;  0 = none, 1 = /U, 2 = /S, 4 = /M or /C and AL = x, and FF = error.
  359. ;  Return carry clear if valid, set if invalid.
  360. ;  Changes:    AX,BX,CX,DX,SI,DI
  361. ;----------------------------------------------------------------------
  362. WHITE        DB    " ,;",9            ;Space,comma,semi,tab
  363. WHITE_LEN    EQU    $ - OFFSET WHITE
  364.  
  365. CMD_LINE    PROC    NEAR
  366.     ASSUME    CS:CSEG, DS:CSEG, ES:CSEG
  367.  
  368.         XOR    DH,DH            ;Accumulate flags here
  369.         MOV    SI,80H            ;Length of cmd line
  370.         LODSB                ;Get byte in AL
  371.         OR    AL,AL            ;If parameters
  372.         JNZ    CMD_1            ; process them
  373. CMD_0:
  374.         CLC                ;Clear carry = no error
  375.         MOV    AH,DH            ;Load flags
  376.         RET                ;Return
  377. CMD_1:
  378. ;----------------------------------------------------------------------
  379. ;  Something is on the line.  Let's find out what.
  380. ;----------------------------------------------------------------------
  381.         MOV    BL,AL            ;Put char count in BL
  382. CMD_2:
  383.         OR    BL,BL            ;Any more chars?
  384.         JZ    CMD_0            ;If not, exit
  385.  
  386.         LODSB                ;Get character in AL
  387.         DEC    BL            ;Adjust count
  388.         MOV    DI,OFFSET WHITE        ;Compare to these
  389.         MOV    CX,WHITE_LEN        ;Number to check
  390.         REPNE    SCASB
  391.         JE    CMD_2            ;Jump if char was white
  392.  
  393.         CMP    AL,"/"            ;Is the char a slash?
  394.         JE    CMD_4            ;Yes, process switch
  395. CMD_ERR:
  396.         MOV    AH,ERR_SW        ;Signal error
  397.         STC                ;Carry on
  398.         RET                ;Return
  399.  
  400. ;----------------------------------------------------------------------
  401. ; char was slash.  Get and process switch in an inelegant fashion.
  402. ;----------------------------------------------------------------------
  403. CMD_4:
  404.         OR    BL,BL            ;Switch must follow /
  405.         JZ    CMD_ERR            ;If not, error
  406.  
  407.         LODSB                ;Get switch
  408.         DEC    BL            ;Reduce count
  409.         AND    AL,NOT 20H        ;Make switch upper case
  410.  
  411.         CMP    AL,"U"            ;Request to uninstall
  412.         JE    CMD_5            ; jump if /U
  413.  
  414.         CMP    AL,"S"            ;Setup
  415.         JE    CMD_6            ; jump if /S
  416.  
  417.         CMP    AL,"M"            ;Escape char
  418.         JE    CMD_7            ; jump if /M
  419.  
  420.         CMP    AL,"C"            ;escape Char
  421.         JE    CMD_9            ; jump if /C
  422.  
  423.         JMP    CMD_ERR            ;No more legal options
  424. CMD_5:
  425.         OR    DH,U_SW            ;Set bit
  426.         JMP    CMD_2            ;Continue scan
  427. CMD_6:
  428.         OR    DH,S_SW            ;Set bit
  429.         JMP    CMD_2            ;Continue scan
  430. CMD_7:
  431.         OR    BL,BL            ;Does a char follow?
  432.         JZ    CMD_ERR            ;No, syntax error
  433.  
  434.         LODSB                ;Get new escape char
  435.         DEC    BL            ;Reduce parm count
  436. CMD_8:
  437.         MOV    ESC_CHAR,AL        ;Save in load copy
  438.         JMP    CMD_2            ;Continue scan
  439. CMD_9:
  440.         MOV    CX,3            ;Number of digits to read
  441.         MOV    BH,10            ;Constant to multiply by
  442.         XOR    AX,AX            ;Set AX=0
  443.         MOV    DI,AX            ;    DI=0
  444. CMD_10:
  445.         OR    BL,BL            ;Does a char follow?
  446.         JZ    CMD_ERR            ;No, syntax error
  447.  
  448.         LODSB                ;Get a digit in AL
  449.         DEC    BL            ;Adjust count
  450.  
  451.         SUB    AL,"0"            ;Make into a number
  452.         CMP    AL,9            ;Make sure it's valid
  453.         JA    CMD_ERR            ; else error
  454.  
  455.         XCHG    DI,AX            ;Get total in AX
  456.         MUL    BH            ;Multiply by 10
  457.         ADD    DI,AX            ;Add new digit
  458.         LOOP    CMD_10
  459.  
  460.         MOV    AX,DI            ;Get char in AL
  461.         JMP    CMD_8            ; and save it
  462.  
  463. CMD_LINE    ENDP
  464.  
  465.  
  466. ;======================================================================
  467. ;  The UNLOAD proc will look for a copy of ASPRN in memory that has the
  468. ;  same macro character, and unload if found. Carry clear if successful.
  469. ;  Set if error and DX points to error msg to display.
  470. ;----------------------------------------------------------------------
  471. UNLOAD        PROC    NEAR
  472.     ASSUME    CS:CSEG, DS:CSEG, ES:CSEG
  473.  
  474. ;----------------------------------------------------------------------
  475. ;  Check if already loaded in memory.  Don't load multiple copies.
  476. ;  When search terminates
  477. ;    ES = BX = segment of first matching copy found in memory.
  478. ;    CS = DS = AX = segment of current copy as loaded from disk.
  479. ;  If no previous copy found
  480. ;    CS = ES = AX = BX
  481. ;  If previous copy IS found
  482. ;    (CS = DS = AX) != (ES = BX)
  483. ;----------------------------------------------------------------------
  484.         CALL    FIND_RES        ;Look for resident copy
  485.     ASSUME    ES:NOTHING            ;May be changed by proc
  486.  
  487.         MOV    DX,OFFSET NOT_RES$    ;Default error msg
  488.         JNC    UNLOAD_1        ;NC if successful, jump
  489.         RET                ;Return with carry set
  490.  
  491. ;----------------------------------------------------------------------
  492. ;  A previous copy was found in memory. Now CS=DS=new copy. ES=BX=old
  493. ;  copy.  Get the segment for the current printer interrupt.  If it's
  494. ;  the same as the seg of the resident copy, then we can deinstall.
  495. ;----------------------------------------------------------------------
  496. UNLOAD_1:
  497.         PUSH    BX            ;Save resident segment
  498.  
  499.         MOV     AX,3517H        ;Get current BIOS prn INT
  500.         INT    21H            ;Result in ES:BX
  501.  
  502.         POP    BX            ;Discard offset, retrieve
  503.                         ; resident segment
  504.  
  505.         MOV    DX,OFFSET CANT_GO$    ;Default error message
  506.  
  507.         MOV    AX,ES            ;Int 17 segment in AX (ES)
  508.         CMP    AX,BX            ; same as resident segment?
  509.  
  510.         JE    UNLOAD_2        ;Yes, remove
  511.  
  512. ;----------------------------------------------------------------------
  513. ;  Another program has intercepted the printer and we cannot deinstall.
  514. ;  Turn on the panic switch so that we'll be meerly disabled.
  515. ;----------------------------------------------------------------------
  516. UNLOAD_1A:
  517.         PUSH    BX            ;Point to resident
  518.         POP    ES            ; segment again
  519.         MOV    ES:PANIC_FLAG,0FFH    ;Disable expander
  520.         STC                ;Indicate error
  521.         RET                ;Return
  522.  
  523. ;----------------------------------------------------------------------
  524. ;  No other TSRs are loaded after us.  Perform the removal.
  525. ;  1.  Restore Int 17h to its previous value.
  526. ;  2.  Release the MCB that we allocated to hold the strings.
  527. ;  3.  If code seg different than string block, release MCB for program.
  528. ;  Note that ES points to the resident segment.
  529. ;----------------------------------------------------------------------
  530. UNLOAD_2:
  531.         LDS    DX,DWORD PTR ES:OLD_INT17 ;Get saved vector
  532.     ASSUME    DS:NOTHING            ;Changes DS
  533.         MOV    AX,2517H        ;Restore it
  534.         INT    21H            ; Thru DOS
  535.  
  536.         LES    AX,DWORD PTR ES:STRING_LOC ;String segment in ES
  537.         MOV    AH,49H            ;Free strings block
  538.         INT    21H            ;Release seg in ES
  539.         JC    UNLOAD_1A        ;Panic if error
  540.  
  541.         MOV    AX,ES            ;Move seg to AX
  542.         CMP    AX,BX            ;If = program segment
  543.         JE    UNLOAD_3        ; return
  544.  
  545.         MOV    ES,BX            ;Free res code
  546.         MOV    AH,49H            ;Free strings
  547.         INT    21H            ; Thru DOS
  548.         JC    UNLOAD_1A        ;Panic if error
  549. UNLOAD_3:
  550.         CLC                ;Clear carry flag
  551.  
  552.         PUSH    CS            ;Reset DS and ES
  553.         POP    DS            ; back to CS
  554.         PUSH    CS
  555.         POP    ES
  556.         RET
  557.  
  558. UNLOAD        ENDP
  559.  
  560.  
  561. ;======================================================================
  562. ;  Search memory to see if a copy of this program has already been
  563. ;  loaded by looking for copyright notice.
  564. ;  If found, NC, CS = DS = AX = LOAD COPY, ES = BX = RES COPY
  565. ;  If not    CY, CS = DS = AX = ES = BX = LOAD COPY
  566. ;----------------------------------------------------------------------
  567. FIND_RES    PROC    NEAR
  568.     ASSUME    CS:CSEG, DS:CSEG, ES:NOTHING
  569.  
  570.         CLD                ;String moves forward
  571.         NOT    WORD PTR [ENTPT]    ;Modify to avoid false match
  572.  
  573.         MOV    BX,600H            ;BX = segment to compare
  574.         MOV    AX,CS            ;AX = our segment
  575. FIND_RES_1:
  576.         INC    BX            ;Next paragraph
  577.         MOV    ES,BX            ;Set ES to search segment
  578.         CMP    AX,BX            ;If not load copy
  579.         JNE    FIND_RES_2        ; test for copyright
  580.         STC                ;Else, flag failure
  581.         RET
  582. FIND_RES_2:
  583.         MOV    SI,OFFSET ENTPT        ;String to compare
  584.         MOV    DI,SI            ;Offset is same
  585.         MOV    CX,16            ;Compare first 16 bytes
  586.         REP    CMPSB            ;CMP DS:SI TO ES:DI
  587.         OR    CX,CX            ;All matched?
  588.         JNZ    FIND_RES_1        ;No, continue search
  589.  
  590.         CLC                ;Set NC = success
  591.         RET
  592.  
  593. FIND_RES    ENDP
  594.  
  595.  
  596. ;======================================================================
  597. ;  The program has been loaded normally, and is already resident.
  598. ;  Just replace the old strings with the new strings.
  599. ;  ES = BX = TSR segment
  600. ;----------------------------------------------------------------------
  601. BADREPLACE$    DB    CR,LF,"ASPRN Failed. Suggest Reboot.",CR,LF,"$"
  602. NEWSEGLEN    DW    0
  603.  
  604. REPLACE        PROC    NEAR
  605.     ASSUME    CS:CSEG, DS:CSEG, ES:NOTHING
  606.  
  607. ;----------------------------------------------------------------------
  608. ;  If the old string segment (as recorded in old copy) is the same as
  609. ;  the resident program segment, then they must be chopped off.
  610. ;----------------------------------------------------------------------
  611.         MOV    AH,50H            ;Set active PSP
  612.         MOV    BX,ES            ; to TSR
  613.         INT    21H            ;Undocumented DOS
  614.  
  615.         MOV    AX,ES:STRING_LOC[2]    ;Is old string segment
  616.         CMP    AX,BX            ; same as old prog seg?
  617.         JE    REPLACE_1        ;Yes, cut them off.
  618.  
  619. ;----------------------------------------------------------------------
  620. ;  The strings are in a separate block, so we can just release them.
  621. ;----------------------------------------------------------------------
  622.         PUSH    ES            ;Save ES
  623.  
  624.         MOV    ES,AX            ;Segment to release
  625.         MOV    AH,49H            ;Free allocated memory
  626.         INT    21H            ; Thru DOS
  627.  
  628.         POP    ES            ;Restore segment
  629.  
  630.         JNC    REPLACE_2        ;Continue if no erro
  631.         JMP    REPLACE_4
  632.  
  633. ;----------------------------------------------------------------------
  634. ;  Strings are still attaced to the old ASPRN.COM file.  We must surgically
  635. ;  remove them.  Shrink the old ES block down to hold just the program.
  636. ;----------------------------------------------------------------------
  637. REPLACE_1:
  638.         MOV    BX,(OFFSET MINIMUM - OFFSET CSEG + 15) SHR 4
  639.         MOV    AH,4AH            ;Setblock
  640.         INT    21H            ;Shrink ES
  641.         JC    REPLACE_4
  642.  
  643. ;----------------------------------------------------------------------
  644. ;  Try to locate a block large enough to contain the strings below
  645. ;  current program (in lower memory).
  646. ;----------------------------------------------------------------------
  647. REPLACE_2:
  648.         CALL    FIND_LOW        ;Look for memory block
  649.         JC    REPLACE_3        ;Jump if not found
  650.  
  651. ;----------------------------------------------------------------------
  652. ;  Room was found. The new segment was returned in AX.
  653. ;  Relocate the strings.  Update the pointers in the resident copy.
  654. ;----------------------------------------------------------------------
  655.         CALL    MOVE_STRINGS        ;Copy strings to block
  656.  
  657.         MOV    AH,50H            ;Set active PSP
  658.         MOV    BX,CS            ; to US
  659.         INT    21H            ; Thru DOS
  660. REPLACE_2A:
  661.         MOV    AX,4C00H        ;All done! Terminate.
  662.         INT    21H            ; Thru DOS
  663.  
  664. ;======================================================================
  665. ;  There is no room in low memory, so we want to relocate our strings
  666. ;  to the lowest possible address.  We currently own all high memory.
  667. ;  Shrink this copy's memory down to just enough to hold the program,
  668. ;  strings, and STACK.
  669. ;----------------------------------------------------------------------
  670. REPLACE_3:
  671.         MOV    AH,50H            ;Set active PSP
  672.         MOV    BX,CS            ; back to us
  673.         INT    21H            ; Undocumented DOS
  674.  
  675.         PUSH    ES            ;Save register
  676.  
  677.         MOV    AH,4AH            ;Change size of blcok
  678.         MOV    BX,(OFFSET LASTBYTE - OFFSET CSEG + 15) SHR 4
  679.         MOV    NEWSEGLEN,BX        ;Save this size
  680.  
  681.         PUSH    CS            ;Set ES to CS
  682.         POP    ES            ; i.e., segment to modify
  683.         INT    21H            ; Shrink thru DOS
  684.  
  685.         POP    ES            ;Retrive TSR segment
  686.         JNC    REPLACE_5
  687. REPLACE_4:
  688.         MOV    DX,OFFSET BADREPLACE$    ;Indicate an error
  689.         MOV    AH,9            ;Display string
  690.         INT    21H            ; Thru DOS
  691.  
  692.         MOV    ES:PANIC_FLAG,0FFH    ;Disable expander
  693.  
  694.         MOV    AX,4CFFH        ;Terminate with error
  695.         INT    21H            ; Thru DOS
  696.  
  697.  
  698.  
  699. ;----------------------------------------------------------------------
  700. ;  Ask for 640K.  We'll get an error and BX will contain the largest
  701. ;  piece of memory available.  One of the better DOS functions returns.
  702. ;  New block will be above us.  Allocate all of it.
  703. ;----------------------------------------------------------------------
  704. REPLACE_5:
  705.         MOV    AH,48H            ;Allocate memory
  706.         MOV    BX,0FFFFH        ;Ask for 640K
  707.         INT    21H            ;Available returned in BX
  708.  
  709.         CMP    BX,(OFFSET LASTBYTE - OFFSET CSEG + 15) SHR 4
  710.         JB    REPLACE_4
  711.  
  712.         MOV    AH,48H            ;Allocate BX (all) paras
  713.         INT    21H            ;AX = new segment
  714.         JC    REPLACE_4
  715.  
  716. ;----------------------------------------------------------------------
  717. ;  Duplicate the program at the new address.  Copy from ds:si to es:di
  718. ;----------------------------------------------------------------------
  719.         XOR    SI,SI            ;SI = 0
  720.         MOV    DI,SI            ;DI = 0
  721.         PUSH    ES            ;Save TSR segment
  722.  
  723.         MOV    ES,AX            ;New block
  724.         MOV    CX,OFFSET LASTBYTE    ;Bytes to move
  725.         CLD
  726.         REP    MOVSB            ;Copy to new address
  727.  
  728.         POP    ES
  729.  
  730. ;----------------------------------------------------------------------
  731. ;  Now, hop up to our new home by using a far return.
  732. ;----------------------------------------------------------------------
  733.         PUSH    AX            ;Put new CS on stack
  734.         MOV    DX,OFFSET TARGET    ;And address of the
  735.         PUSH    DX            ; next instruction
  736.         CLI                ;Turn off interrupts
  737.  
  738.         DB    0CBH            ;Opcode for RETF
  739.  
  740. ;----------------------------------------------------------------------
  741. ;  Now we're at AX:TARGET, in the copy of the program.  Make it real.
  742. ;----------------------------------------------------------------------
  743. TARGET:
  744.         PUSH    CS            ;Move stack - lose old
  745.         POP    SS            ;Change segment
  746.         MOV    SP,OFFSET STACK_TOP    ; and offset
  747.         STI                ;Allow interrrupts
  748.  
  749.         MOV    BX,AX            ;Get the new PSP
  750.         MOV    AH,50H            ;Set active PSP
  751.         INT    21H            ; Undocumented DOS
  752.  
  753. ;----------------------------------------------------------------------
  754. ;  Release the memory held by the old copy of the program at DS.
  755. ;----------------------------------------------------------------------
  756.         PUSH    ES            ;Save register
  757.  
  758.         PUSH    DS            ;Put loaded PSP seg
  759.         POP    ES            ; in ES
  760.  
  761.         MOV    AH,49H            ;Free memory
  762.         INT    21H            ; Thru DOS
  763.  
  764.         POP    ES            ;Restore register
  765.         JC    REPLACE_4        ;Panic if error
  766.  
  767.         PUSH    CS            ;Set DS to this new seg
  768.         POP    DS
  769.  
  770. ;----------------------------------------------------------------------
  771. ;  Now find the a block for the strings.
  772. ;----------------------------------------------------------------------
  773. BREAKPT:
  774.         MOV    AH,50H            ;Block must belong to
  775.         MOV    BX,ES            ; resident copy
  776.         INT    21H
  777.  
  778.         CALL    FIND_LOW
  779.  
  780. ;----------------------------------------------------------------------
  781. ;  Copy strings from the new copy at CS:STRINGS newly allocated block.
  782. ;  Point ES to the RES copy to update the parameters.
  783. ;----------------------------------------------------------------------
  784.         CALL    MOVE_STRINGS        ;Transfer strings
  785.  
  786. ;----------------------------------------------------------------------
  787. ;  Terminate through bogus PSP.
  788. ;----------------------------------------------------------------------
  789.         MOV    AH,50H            ;Set active PSP
  790.         MOV    BX,CS            ; to right here
  791.         INT    21H            ;Undocumented DOS again
  792.  
  793.         PUSH    CS            ;Point ES to the
  794.         POP    ES            ; current segment
  795.  
  796.         MOV    AH,4AH            ;Setblock
  797.         MOV    BX,NEWSEGLEN        ;Same size
  798.         INT    21H            ; Thru DOS
  799.         JC    REPLACE_4        ;Panic if error
  800.  
  801.         MOV    AX,4C00H        ;Terminate thru new PSP
  802.         INT    21H            ; Thru DOS
  803.  
  804. REPLACE        ENDP
  805.  
  806.  
  807. ;======================================================================
  808. ;  Look for a piece of memory large enough to hold DS:STRING_LEN bytes.
  809. ;  This is always taken from the newest program being loaded.
  810. ;  Changes:    AX,BX,CL
  811. ;----------------------------------------------------------------------
  812. FIND_LOW    PROC    NEAR
  813.     ASSUME    CS:CSEG, DS:CSEG, ES:NOTHING
  814.  
  815.         MOV    AH,48H            ;Allocate memory
  816.         MOV    BX,STRING_LEN        ;Change length in bytes
  817.         ADD    BX,15
  818.         MOV    CL,4
  819.         SHR    BX,CL            ; to paras
  820.         INT    21H            ; Thru DOS
  821.  
  822.         RET
  823.  
  824. FIND_LOW    ENDP
  825.  
  826.  
  827. ;======================================================================
  828. ;  Relocate the strings from DS:STRINGS TO AX:0.  Update the pointer
  829. ;  and length in the resident copy.
  830. ;----------------------------------------------------------------------
  831. MOVE_STRINGS    PROC    NEAR
  832.     ASSUME    CS:CSEG, DS:CSEG, ES:NOTHING
  833.  
  834.         PUSH    ES            ;Save resident segment
  835.  
  836.         MOV    CX,STRING_LEN        ;Bytes to move
  837.         MOV    ES:STRING_LEN,CX    ;Update resident copy
  838.  
  839.         XOR    DI,DI            ;Copy to offset 0
  840.         MOV    ES:STRING_LOC[0],DI    ;New offset
  841.  
  842.         MOV    ES:STRING_LOC[2],AX    ;New segment
  843.         MOV    ES,AX            ;Destination is ES:DI
  844.  
  845.         MOV    SI,OFFSET STRINGS    ;Source is DS:SI
  846.         CLD                ;String moves forward
  847.         REP    MOVSB            ; WHAM!
  848.  
  849.         POP    ES            ;Restore segment
  850.         RET
  851.  
  852. MOVE_STRINGS    ENDP
  853.  
  854.  
  855. ;======================================================================
  856. ;  This proc allows you to edit the strings.  On entry CS=DS=ES.
  857. ;  Total of program code + strings cannot exceed 64K, which is the
  858. ;  maximum size of a COM file.
  859. ;----------------------------------------------------------------------
  860. MEMORY$        DB    "Not Enough Memory$"
  861. SAVE$        DB    CR,LF,"Save changes as ASPRNNEW.COM? (Y/N) $"
  862. OVERWRITE$    DB    CR,LF,"Overwrite existing file? (Y/N) $"
  863. FERROR$        DB    CR,LF,"File error. Try Again? (Y/N) $"
  864. WERROR$        DB    CR,LF,"Write error. Try Again? (Y/N) $"
  865.  
  866. FILENAME    DB    "ASPRNNEW.COM",0
  867. COM_PTR        DW    OFFSET STRING_END    ;Cannot exceed 64k-200H
  868.  
  869. ROW_END        DB    24            ;Defaults for
  870. COL_END        DB    80            ; common video
  871. COL_MAX        DB    0            ;Rightmost column
  872. VPAGE        DB    0            ;Active page
  873.  
  874. ATTR        DB    0            ;Selected attribute
  875.  
  876. ;----------------------------------------------------------------------
  877. SETUP        PROC    NEAR
  878.     ASSUME    CS:CSEG, DS:CSEG, ES:CSEG
  879.  
  880.         MOV    AH,4AH            ;Modify memory block
  881.         MOV    BX,1000H        ;Ask for 64K
  882.         INT    21H            ; Thru DOS
  883.         JNC    SETUP_0            ;Jump if no error
  884.  
  885.         MOV    DX,OFFSET MEMORY$    ;Need more room
  886.         MOV    AH,9            ;Display string
  887.         INT    21H            ; Thru DOS
  888.  
  889.         MOV    AX,4C02H        ;Terminate with error
  890.         INT    21H            ; Thru DOS
  891. SETUP_0:
  892.         CLI                ;Disable interrupts
  893.         MOV    SP,0FFFEH        ;Move stack to end of seg
  894.         STI                ;Enable interrupts
  895.  
  896. ;----------------------------------------------------------------------
  897. ;  Editing requires that we be in a text mode.
  898. ;  Clear entire screen to  desired attribute.
  899. ;----------------------------------------------------------------------
  900.         CALL    VIDEO_SETUP        ;Examine video hardware
  901.  
  902.         MOV    AL,COL_END        ;Right edge of screen
  903.         SUB    AL,2            ;(1 based) in one char
  904.         MOV    COL_MAX,AL        ;Is rightmost column
  905.  
  906.         CALL    CLR_BOX            ;Draw the window
  907.  
  908. ;----------------------------------------------------------------------
  909. ;  Invoke the string editor.  Returns when F7 is pressed.
  910. ;----------------------------------------------------------------------
  911.         CALL    EDIT            ;String editor
  912.  
  913.         MOV    CX,COM_PTR        ;Get program length
  914.         SUB    CX,OFFSET STRINGS    ; minus start of strings
  915.         MOV    STRING_LEN,CX        ; is string length
  916.  
  917. ;----------------------------------------------------------------------
  918. ;  Ask if changes should be written out to ASPRNNEW.COM.  If not, just end.
  919. ;----------------------------------------------------------------------
  920. SETUP_1:
  921.         MOV    DX,OFFSET SAVE$        ;Clone the changes?
  922.         CALL    GETRESPONSE        ;Yes or No.
  923.         JC    SETUP_2            ;Yes, continue
  924.  
  925.         MOV    AX,4C03H        ;Terminate normally
  926.         INT    21H            ; Thru DOS
  927.  
  928. ;----------------------------------------------------------------------
  929. ;  Try to open the file to see if it exists.
  930. ;----------------------------------------------------------------------
  931. SETUP_2:
  932.         MOV    AX,3D02H        ;Open file for r/w
  933.         MOV    DX,OFFSET FILENAME    ; This name
  934.         INT    21H            ; Thru DOS
  935.         JC    SETUP_3            ;Jump if not found
  936.  
  937.         MOV    BX,AX            ;Move handle
  938.  
  939.         MOV    DX,OFFSET OVERWRITE$    ;Should we overwrite?
  940.         CALL    GETRESPONSE
  941.         JC    SETUP_4            ;Yes
  942. SETUP_2A:
  943.         MOV    AH,3EH            ;Close file handle
  944.         INT    21H            ; Thru DOS
  945.         JMP    SETUP_1            ;Ask again
  946.  
  947. ;----------------------------------------------------------------------
  948. ;  File does not exist.  Attempt to open as new.
  949. ;----------------------------------------------------------------------
  950. SETUP_3:
  951.         MOV    AH,3CH            ;Create file fn
  952.         XOR    CX,CX            ; for writing
  953.         MOV    DX,OFFSET FILENAME    ; this is name
  954.         INT    21H            ; Thru DOS
  955.         JNC    SETUP_3A        ;Opened OK, jump
  956.  
  957.         MOV    DX,OFFSET FERROR$    ;Error opening file
  958.         CALL    GETRESPONSE        ; try again?
  959.         JC    SETUP_3            ;Yes
  960.         JMP    SETUP_1            ;No
  961. SETUP_3A:
  962.         MOV    BX,AX            ;Put handle in BX
  963.  
  964. ;----------------------------------------------------------------------
  965. ;  A valid file handle is in BX.  Write away.
  966. ;----------------------------------------------------------------------
  967. SETUP_4:
  968.         MOV    AH,40H            ; Write to file fn
  969.         MOV    CX,COM_PTR        ; Length
  970.         SUB    CX,100H            ; Minus PSP length
  971.         MOV    DX,100H            ; Pointer to DTA
  972.         INT    21H            ; Thru DOS
  973.         JC    SETUP_5            ;CY signals error
  974.  
  975.         CMP    AX,CX            ;All bytes written?
  976.         JE    SETUP_6            ;Yes
  977.  
  978. ;----------------------------------------------------------------------
  979. ;  An error was encountered on the write.
  980. ;----------------------------------------------------------------------
  981. SETUP_5:
  982.         MOV    DX,OFFSET WERROR$
  983.         CALL    GETRESPONSE        ;Try again?
  984.         JC    SETUP_4            ;Yes
  985.         JMP    SETUP_2A        ;No
  986.  
  987. ;----------------------------------------------------------------------
  988. ;  File was written okay.  Close and exit.
  989. ;----------------------------------------------------------------------
  990. SETUP_6:
  991.         MOV    AH,3EH            ;Close file handle in BX
  992.         INT    21H            ; Thru DOS
  993.  
  994.         MOV    AX,4C00H        ;Terminate
  995.         INT    21H            ; Thru DOS
  996.  
  997. SETUP        ENDP
  998.  
  999.  
  1000. ;======================================================================
  1001. ;  Accept only a Y or N answer.  Return CY if YES, NC if NO.  DX contains
  1002. ;  offset of prompt to print.
  1003. ;----------------------------------------------------------------------
  1004. GETRESPONSE    PROC    NEAR
  1005.     ASSUME    CS:CSEG, DS:CSEG, ES:CSEG
  1006.  
  1007.         MOV    AH,9            ;Display string fn
  1008.         INT    21H            ; Thru DOS
  1009. GETR_0:
  1010.         CALL    GETKEY            ;Get a keystroke
  1011.  
  1012.         AND    AL,NOT 20H        ;Capitalize
  1013.  
  1014.         CMP    AL,"N"            ;If NO,
  1015.         JNE    GETR_1
  1016.                         ;If equal, CY is off
  1017.         RET                ; just end
  1018. GETR_1:
  1019.         CMP    AL,"Y"            ;If not YES,
  1020.         JNE    GETR_0            ; try again
  1021.         STC                ;Carry on
  1022.         RET
  1023.  
  1024. GETRESPONSE    ENDP
  1025.  
  1026.  
  1027. ;======================================================================
  1028. ;  Determine all the paramters and info we need to handle the display.
  1029. ;  Return with carry set if incomaptible mode.
  1030. ;----------------------------------------------------------------------
  1031. COLOR_ATTR    EQU    1FH            ;Brite white/blue
  1032. BW_ATTR        EQU    07H            ;Reverse video
  1033.  
  1034. VIDEO_SETUP    PROC    NEAR
  1035.     ASSUME    CS:CSEG, DS:CSEG, ES:CSEG
  1036.  
  1037.         MOV    AH,0FH            ;Get video mode
  1038.         INT    10H            ; Thru BIOS
  1039.  
  1040.         MOV    ATTR,COLOR_ATTR        ;Assume color screen
  1041.  
  1042.         CMP    AL,3            ;CGA video modes
  1043.         JBE    VID_3            ; are okay
  1044.  
  1045.         CMP    AL,7            ;MDA text mode
  1046.         JE    VID_2            ; is okay, too.
  1047.  
  1048.         STC                ;Else, an error
  1049.         RET                ;Return
  1050. VID_2:
  1051.         MOV    ATTR,BW_ATTR        ;Force B/W
  1052. VID_3:
  1053.         MOV    COL_END,AH        ;Save cols
  1054.         MOV    VPAGE,BH        ;Save current page
  1055.  
  1056. ;----------------------------------------------------------------------
  1057. ;  Determine if an EGA/VGA adapter is installed, and find row count.
  1058. ;----------------------------------------------------------------------
  1059.         MOV    AH,12H            ;EGA alternate select
  1060.         MOV    BL,10H            ;Return EGA info
  1061.         INT    10H            ;Thru BIOS
  1062.         CMP    BL,10H            ;If BL unchanged
  1063.         MOV    DL,24            ;Set default rows
  1064.         JE    VID_4            ; there's no EGA/VGA
  1065.  
  1066.         PUSH    ES            ;Changed by call
  1067.         MOV    AX,1130H        ;EGA info call
  1068.         MOV    BH,0            ;Dummy argument
  1069.         INT    10H            ; thru BIOS
  1070.         POP    ES
  1071. VID_4:
  1072.         MOV    ROW_END,DL        ;Save rows
  1073.         CLC
  1074.         RET
  1075.  
  1076. VIDEO_SETUP    ENDP
  1077.  
  1078. ;======================================================================
  1079. ;  Position the cursor to the stored values.
  1080. ;  Changes BX
  1081. ;----------------------------------------------------------------------
  1082. CUR_SET        PROC    NEAR
  1083.     ASSUME    CS:CSEG, DS:CSEG, ES:NOTHING
  1084.  
  1085.         PUSH    AX            ;Save used register
  1086.  
  1087.         MOV    AH,2            ;Position cursor fn
  1088.         MOV    BH,VPAGE        ; current page
  1089.         MOV    DX,CURSOR_POS        ; new cursor position
  1090.         INT    10H            ; Thru BIOS
  1091.  
  1092.         POP    AX            ;Restore register
  1093.         RET
  1094.  
  1095. CUR_SET        ENDP
  1096.  
  1097. ;======================================================================
  1098. ;  The EDIT procedure handles all the editing. It keeps track of the
  1099. ;  current macro strings and displays them on the screen as they change.
  1100. ;----------------------------------------------------------------------
  1101.  
  1102. ; The PTR offset points to the character that appears at the left side
  1103. ; of the window
  1104.  
  1105. PTR_ARRAY    LABEL    WORD            ;Indicates the starting
  1106. NAM_PTR        DW    0            ; offset of the current
  1107. STR_PTR        DW    0            ; macro name and string
  1108.  
  1109. ACTIVE        DW    0            ;Index for array
  1110.  
  1111. ;  The screen column for positioning the cursor. Common data.
  1112.  
  1113. CURSOR_POS    LABEL    WORD
  1114. CURSOR_COL    DB    6            ;Current cursor
  1115. CURSOR_ROW    DB    0            ; position
  1116.  
  1117. MACRO_PTR    DB    0            ;Pointer to string set
  1118.  
  1119. INS_STATE    DB    0            ;0=INS FF=TYPEOVER
  1120.  
  1121. ;======================================================================
  1122. EDIT        PROC    NEAR
  1123.     ASSUME    CS:CSEG, DS:CSEG, ES:CSEG
  1124.  
  1125.         MOV    MACRO_PTR,0        ;Choose first string
  1126.  
  1127. ;----------------------------------------------------------------------
  1128. ;  Display the Macro letter for these strings.
  1129. ;----------------------------------------------------------------------
  1130. EDIT_1:
  1131.         MOV    CURSOR_POS,0106H    ;Move to row 1 col 2
  1132.         CALL    CUR_SET
  1133.  
  1134.         MOV    AH,0AH            ;Write character
  1135.         MOV    AL,ESC_CHAR        ; char to write
  1136.         MOV    CX,1            ; repeat count
  1137.         INT    10H            ; Thru BIOS
  1138.  
  1139.         INC    CURSOR_COL        ;Move to next column
  1140.         CALL    CUR_SET
  1141.  
  1142.         MOV    AH,0AH            ;Write character
  1143.         MOV    AL,MACRO_PTR        ; number of macro
  1144.         ADD    AL,"A"            ; convert to letter
  1145.         MOV    CX,1            ; repeat count
  1146.         INT    10H            ; Thru BIOS
  1147.  
  1148. ;----------------------------------------------------------------------
  1149. ;  Initialize the pointers to point to the first macro set.
  1150. ;----------------------------------------------------------------------
  1151.         CALL    LOAD_POINTERS
  1152.  
  1153. ;----------------------------------------------------------------------
  1154. ;  Display the selected strings on the screen as read from memory.
  1155. ;----------------------------------------------------------------------
  1156.         MOV    BX,0            ;Index for Name
  1157.  
  1158.         CALL    MAKE_ACTIVE        ;Put cursor in NAME
  1159.         CALL    DISPLAY            ;Show the string
  1160.  
  1161.         MOV    BX,2            ;Index for Macro
  1162. EDIT_2:
  1163.         CALL    MAKE_ACTIVE        ;Put cursor in MACRO
  1164.         CALL    DISPLAY            ;Show the string
  1165.  
  1166. ;----------------------------------------------------------------------
  1167. ;  Get a key from the keyboard and act on it.
  1168. ;----------------------------------------------------------------------
  1169. KEY_0:
  1170.         CALL    GETKEY            ;Read a key into AX
  1171.  
  1172.         OR    AL,AL            ;If 0, is extended
  1173.         JZ    KEY_2            ; which means command
  1174.  
  1175.         CMP    AX,BS            ;If not actual BS key
  1176.         JNE    KEY_1            ;Process as char
  1177.  
  1178.         OR    AH,AH            ;If high byte is zero
  1179.         JZ    KEY_1            ;Process as char
  1180.  
  1181. ;----------------------------------------------------------------------
  1182. ;  The backspace key is the only key that requires special handling.
  1183. ;  Treat BS as a CURSOR-LEFT/DELETE combination.
  1184. ;----------------------------------------------------------------------
  1185.         CALL    CURSOR_LEFT
  1186.         JC    KEY_0
  1187. KEY_0A:
  1188.         CALL    STRING_DEL        ;Delete char at cursor
  1189.         JC    KEY_0
  1190.  
  1191.         CALL    DISPLAY
  1192.  
  1193.         CMP    ACTIVE,0        ;If deleted from first
  1194.         JNE    KEY_0
  1195.  
  1196.         DEC    PTR_ARRAY[2]        ;Back up second
  1197.         JMP    KEY_0
  1198.  
  1199. ;----------------------------------------------------------------------
  1200. ;  Put the character on the screen and in the string.
  1201. ;----------------------------------------------------------------------
  1202. KEY_1:
  1203.         CMP    INS_STATE,0        ;If insert
  1204.         JE    KEY_1A            ; jump
  1205.  
  1206. ;----------------------------------------------------------------------
  1207. ;  If at end of string, typeover works just like insert.
  1208. ;----------------------------------------------------------------------
  1209.         CALL    LOCATE_SI        ;If current char
  1210.         CMP    BYTE PTR [SI],0        ; isn't a zero byte
  1211.         JNZ    KEY_1B            ; just overwrite
  1212. KEY_1A:
  1213.         CALL    STRING_INS        ;Create hole at cursor
  1214.         CMP    ACTIVE,0        ;If inserting first
  1215.         JNE    KEY_1B
  1216.  
  1217.         INC    PTR_ARRAY[2]        ;Advance second
  1218. KEY_1B:
  1219.         CALL    PUTCHAR            ;Put AL at cursor
  1220.         CALL    DISPLAY            ;Show changes
  1221.                         ;Fall through
  1222. ;----------------------------------------------------------------------
  1223. ;  ->  Move the cursor to the right one space.
  1224. ;----------------------------------------------------------------------
  1225. KEY_1C:
  1226.         CALL    CURSOR_RIGHT        ;Move cursor along
  1227.         JMP    KEY_0
  1228.  
  1229. ;----------------------------------------------------------------------
  1230. ;  Key is an extended key.  Must be an instruction.
  1231. ;----------------------------------------------------------------------
  1232. KEY_2:
  1233.         CMP    AH,F7KEY        ;F7 is the exit key
  1234.         JNE    KEY_3
  1235.  
  1236.         MOV    CURSOR_COL,0        ;Reposition cursor
  1237.         MOV    CURSOR_ROW,NROW        ; for message
  1238.         CALL    CUR_SET
  1239.  
  1240.         RET                ; and the only way out
  1241.  
  1242. ;----------------------------------------------------------------------
  1243. ;  All remaining key dispatch done from here.
  1244. ;----------------------------------------------------------------------
  1245. KEY_3:
  1246.         MOV    BL,MACRO_PTR        ;Number of set
  1247.  
  1248.         CMP    AH,DEL            ;Kill char at cursor
  1249.         JE    KEY_0A
  1250.  
  1251.         CMP    AH,PGUP            ;Check for PgUp
  1252.         JE    KEY_3A            ; else check next
  1253.  
  1254.         CMP    AH,PGDN            ;Move to next macro
  1255.         JE    KEY_5
  1256.  
  1257.         MOV    BX,ACTIVE
  1258.  
  1259.         CMP    AH,RARROW        ;Move right 1 char
  1260.         JE    KEY_1C
  1261.  
  1262.         CMP    AH,LARROW        ;Move left
  1263.         JE    KEY_9
  1264.  
  1265.         CMP    AH,UARROW        ;Move up
  1266.         JE    KEY_12
  1267.  
  1268.         CMP    AH,DARROW        ;Move down
  1269.         JE    KEY_14
  1270.  
  1271.         CMP    AH,INS            ;Use Insert mode
  1272.         JE    KEY_15
  1273.  
  1274.         CMP    AH,ENDKEY        ;Move to end of string
  1275.         JE    KEY_16
  1276.  
  1277.         CMP    AH,HOME            ;Move to start of string
  1278.         JE    KEY_17
  1279.  
  1280.         JMP    KEY_0            ;Didn't recongnize it
  1281.  
  1282. ;----------------------------------------------------------------------
  1283. ;  PgUp key:  Move to the previous macro.
  1284. ;----------------------------------------------------------------------
  1285. KEY_3A:
  1286.         DEC    BL            ;Back up
  1287.         CMP    BL,0            ;If below 0
  1288.         JGE    KEY_4
  1289.  
  1290.         MOV    BL,25            ; reset to end
  1291. KEY_4:
  1292.         MOV    MACRO_PTR,BL        ;Update pointer
  1293.         JMP    EDIT_1            ;Start over
  1294.  
  1295. ;----------------------------------------------------------------------
  1296. ;  PgDn key:  Move to the next macro.
  1297. ;----------------------------------------------------------------------
  1298. KEY_5:
  1299.         INC    BL            ;Go forward
  1300.         CMP    BL,25            ;If past end
  1301.         JBE    KEY_4
  1302.  
  1303.         XOR    BL,BL            ;Reset
  1304.         JMP    KEY_4
  1305.  
  1306. ;----------------------------------------------------------------------
  1307. ;  <-  Move the cursor to the left one space.
  1308. ;----------------------------------------------------------------------
  1309. KEY_9:
  1310.         CALL    CURSOR_LEFT        ;Move cursor left
  1311. KEY_10:
  1312.         JMP    KEY_0            ;Failed, ignore it
  1313.  
  1314. ;----------------------------------------------------------------------
  1315. ;  ^   Move to the NAME field.
  1316. ;----------------------------------------------------------------------
  1317. KEY_12:
  1318.         CMP    BX,0            ;If already active
  1319.         JE    KEY_10            ; ignore
  1320.  
  1321.         MOV    BX,0            ;Else, switch
  1322.         JMP    EDIT_2
  1323.  
  1324. ;----------------------------------------------------------------------
  1325. ;  v   Move to the STRING field.
  1326. ;----------------------------------------------------------------------
  1327. KEY_14:
  1328.         CMP    BX,2            ;If already active
  1329.         JE    KEY_10            ; ignore
  1330.  
  1331.         MOV    BX,2            ;else, switch
  1332.         JMP    EDIT_2
  1333.  
  1334. ;----------------------------------------------------------------------
  1335. ;  Toggle the insert/typeover state.
  1336. ;----------------------------------------------------------------------
  1337. KEY_15:
  1338.         NOT    INS_STATE        ;Toggle the flag
  1339.         JMP    KEY_0
  1340.  
  1341. ;----------------------------------------------------------------------
  1342. ;  Move to end of string.
  1343. ;----------------------------------------------------------------------
  1344. KEY_16:
  1345.         CALL    CURSOR_RIGHT        ;Move to the right
  1346.         JNC    KEY_16            ; as long as successful
  1347.         JMP    KEY_0
  1348.  
  1349. ;----------------------------------------------------------------------
  1350. ;  Move to start of string.
  1351. ;----------------------------------------------------------------------
  1352. KEY_17:
  1353.         CALL    CURSOR_LEFT        ;Move to the left
  1354.         JNC    KEY_17            ; as long as successful
  1355.         JMP    KEY_0
  1356.  
  1357. EDIT        ENDP
  1358.  
  1359.  
  1360. ;======================================================================
  1361. ;  Clear a window (box) for our information on the screen.
  1362. ;  Add a border for a nice touch.
  1363. ;----------------------------------------------------------------------
  1364. TITLE$        DB    0B5H,"ASPRN 1.0",0C6H,0
  1365. TITLE_LEN    EQU    $-TITLE$
  1366. HELP$        DB    "STRING: ",27,32,26," INS DEL ",24,32,25
  1367.         DB    "  MACRO: PgUp PgDn  F7 = Save",0
  1368. NAME$        DB    "NAME :",0
  1369. MACRO$        DB    "MACRO:",0
  1370.  
  1371. BOX_CHARS    DB    0C9H,0CDH,0BBH,0BAH,020H,0BAH
  1372.         DB    199,196,182,0C8H,0CDH,0BCH
  1373.  
  1374. NROW        EQU    9
  1375.  
  1376. CLR_BOX        PROC    NEAR
  1377.     ASSUME    CS:CSEG, DS:CSEG, ES:NOTHING
  1378.  
  1379.         MOV    AX,0700H        ;Scroll window fn
  1380.         MOV    BH,ATTR            ; clear to this color
  1381.         XOR    CX,CX            ;Start row,col
  1382.         MOV    DH,ROW_END        ;End row,col
  1383.         MOV    DL,COL_END
  1384.         DEC    DL
  1385.         INT    10H            ;Thru BIOS
  1386.  
  1387.         MOV    BH,VPAGE        ;Get active page
  1388.         MOV    SI,OFFSET BOX_CHARS    ;Draw the edit window
  1389.         MOV    DX,CX            ;Cursor from last call
  1390.         MOV    CX,NROW            ;Number of rows to draw
  1391. CB_1:
  1392.         PUSH    CX            ;Save counter
  1393.         MOV    DL,0
  1394.  
  1395.         MOV    AH,2            ;Position cursor
  1396.         INT    10H            ;Thru BIOS
  1397.  
  1398.         LODSB                ;Get leftmost char
  1399.         MOV    AH,0EH            ;Write char TTY
  1400.         INT    10H            ;Thru BIOS
  1401.  
  1402.         LODSB                ;Get middle char
  1403.         MOV    AH,0AH            ;Write repeated char
  1404.         MOV    CL,COL_END        ;Width of box
  1405.         XOR    CH,CH
  1406.         SUB    CX,2            ; minus 2 sides
  1407.         INT    10H            ;Thru BIOS
  1408.  
  1409.         MOV    AH,2            ;Position cursor
  1410.         MOV    DL,0
  1411.         ADD    DL,COL_END
  1412.         DEC    DL            ;Col = righthand edge
  1413.         INT    10H            ;Thru BIOS
  1414.  
  1415.         LODSB                ;Get rightmost char
  1416.         MOV    AH,0AH            ;Write char
  1417.         MOV    CX,1
  1418.         INT    10H            ;Thru BIOS
  1419.  
  1420.         INC    DH            ;Next row
  1421.         POP    CX            ;Restore counter
  1422.  
  1423.         CMP    CL,NROW            ;Examine row we wrote
  1424.         JE    CB_2            ;If first row
  1425.  
  1426.         CMP    CL,2            ;or next to last
  1427.         JNE    CB_1A            ;Don't adjust count
  1428.         ADD    SI,3
  1429. CB_1A:
  1430.         TEST    CL,1            ;If row is even
  1431.         JZ    CB_2            ;Don't adjust count
  1432.         SUB    SI,6
  1433. CB_2:
  1434.         LOOP    CB_1
  1435.  
  1436.         MOV    CURSOR_ROW,0        ;Top row
  1437.         MOV    AL,COL_MAX        ;Rightmost column
  1438.         SUB    AL,TITLE_LEN+5        ;Backup
  1439.         MOV    CURSOR_COL,AL        ; to here
  1440.  
  1441.         MOV    SI,OFFSET TITLE$    ;Program name
  1442.         CALL    CB_3
  1443.  
  1444.         MOV    CURSOR_POS,0701H
  1445.         MOV    SI,OFFSET HELP$        ;Instructions
  1446.         CALL    CB_3
  1447.  
  1448.         MOV    CURSOR_POS,0301H
  1449.         MOV    SI,OFFSET NAME$        ;And titles
  1450.         CALL    CB_3
  1451.  
  1452.         MOV    CURSOR_POS,0501H
  1453.         MOV    SI,OFFSET MACRO$
  1454. CB_3:
  1455.         CALL    CUR_SET            ;Position cursor
  1456. CB_3A:
  1457.         MOV    BH,VPAGE        ;Use active page
  1458.         LODSB                ;Get a char
  1459.         OR    AL,AL            ;If zero
  1460.         JZ    CB_4            ; quit
  1461.         MOV    AH,0EH            ;Else, write TTY
  1462.         INT    10H            ; Thru BIOS
  1463.         JMP    CB_3A            ;Continue
  1464. CB_4:
  1465.         RET
  1466.  
  1467. CLR_BOX        ENDP
  1468.  
  1469. ;======================================================================
  1470. ;  Write the character in AL to the string as SI.
  1471. ;  Changes:    SI
  1472. ;  Calls:    LOCATE_SI
  1473. ;----------------------------------------------------------------------
  1474. PUTCHAR        PROC    NEAR
  1475.  
  1476.         CALL    LOCATE_SI        ;Point to cursor location
  1477.         MOV    [SI],AL            ; and pop in char
  1478.         RET
  1479.  
  1480. PUTCHAR        ENDP
  1481.  
  1482.  
  1483. ;======================================================================
  1484. ;  Point SI to the same char in the string that is currently above the
  1485. ;  cursor on the screen.
  1486. ;  Changes:    BX,SI,CX
  1487. ;----------------------------------------------------------------------
  1488. LOCATE_SI    PROC    NEAR
  1489.  
  1490.         MOV    BX,ACTIVE        ;Get active index
  1491.         MOV    SI,PTR_ARRAY[BX]    ;Read string from this pt
  1492.  
  1493.         XOR    CH,CH            ;Adjust the start of
  1494.         MOV    CL,CURSOR_COL        ;the string to point
  1495.         SUB    CL,7            ;to the char at the
  1496.         ADD    SI,CX            ;cursor
  1497.  
  1498.         RET
  1499.  
  1500. LOCATE_SI    ENDP
  1501.  
  1502.  
  1503. ;======================================================================
  1504. ;  Create a hole in the string by moving everything to the right.
  1505. ;  Changes:    SI,DI,CX
  1506. ;  Calls:    LOCATE_SI
  1507. ;----------------------------------------------------------------------
  1508. STRING_INS    PROC    NEAR
  1509.  
  1510.         CALL    LOCATE_SI        ;SI = current char
  1511.  
  1512.         MOV    CX,COM_PTR        ;End of strings offset
  1513.         MOV    DI,CX            ;Is also target for move
  1514.         SUB    CX,SI            ;Bytes to move
  1515.  
  1516.         MOV    SI,DI            ;Copy to source register
  1517.         DEC    SI            ;Copy from previous byte
  1518.  
  1519.         STD                ;Move backwards
  1520.         REP    MOVSB            ; whole string
  1521.         INC    COM_PTR            ;File is longer
  1522.  
  1523.         RET
  1524.  
  1525. STRING_INS    ENDP
  1526.  
  1527.  
  1528. ;======================================================================
  1529. ;  Delete the char at the cursor.  Close up the string.
  1530. ;  Changes:    CX,SI,DI
  1531. ;  Calls:    LOCATE_SI
  1532. ;----------------------------------------------------------------------
  1533. STRING_DEL    PROC    NEAR
  1534.  
  1535.         CALL    LOCATE_SI        ;Point to current char
  1536.         CMP    BYTE PTR [SI],0        ;Can't backup too far
  1537.         JNZ    SD_1
  1538.         STC                ;Error
  1539.         RET
  1540. SD_1:
  1541.         MOV    CX,COM_PTR        ;End of strings offset
  1542.         SUB    CX,SI            ;Bytes to move
  1543.         DEC    CX            ;Is one less
  1544.  
  1545.         MOV    DI,SI
  1546.         INC    SI            ;Copy from previous byte
  1547.  
  1548.         CLD                ;Move backwards
  1549.         REP    MOVSB
  1550.         DEC    COM_PTR            ;File gets shorter
  1551.         CLC
  1552.         RET
  1553.  
  1554. STRING_DEL    ENDP
  1555.  
  1556.  
  1557. ;======================================================================
  1558. ;  Move the cursor left/right 1 char.  Return NC if success. CY if fail.
  1559. ;  Changes:    SI,CX
  1560. ;  Calls:    LOCATE_SI, CUR_SET, DISPLAY
  1561. ;----------------------------------------------------------------------
  1562. CURSOR_RIGHT    PROC    NEAR
  1563.  
  1564.         CALL    LOCATE_SI
  1565.         CMP    BYTE PTR [SI],0        ;Are we on last char
  1566.         JNE    CR_0            ;of string? jmp if yes
  1567. CR_A:
  1568.         STC                ;Signal failure
  1569.         RET
  1570. CR_0:
  1571.         MOV    CL,CURSOR_COL
  1572.         CMP    CL,COL_MAX        ;Is cursor at screen edge
  1573.         JE    CR_2            ;yes, jump
  1574.  
  1575.         INC    CL            ;Move to next col
  1576. CR_1:
  1577.         MOV    CURSOR_COL,CL        ;Save (getkey updates)
  1578.         CALL    CUR_SET
  1579.         CLC                ;Signal success
  1580.         RET
  1581. CR_2:
  1582.         INC    PTR_ARRAY[BX]        ;Move the start
  1583.  
  1584.         PUSH    CURSOR_POS        ;Save current cursor
  1585.  
  1586.         MOV    CURSOR_COL,7        ;Redisplay from left side
  1587.         CALL    CUR_SET            ;Set cursor
  1588.         CALL    DISPLAY            ;Draw string
  1589.  
  1590.         POP    CURSOR_POS        ;Reset old cursor
  1591.         CALL    CUR_SET
  1592.         CLC
  1593.         RET
  1594.  
  1595. ;----------------------------------------------------------------------
  1596. CURSOR_LEFT    PROC    NEAR
  1597.  
  1598.         MOV    CL,CURSOR_COL        ;Is cursor
  1599.         CMP    CL,7            ; at 1st column?
  1600.         JE    CL_1            ;Yes, jump
  1601.  
  1602.         DEC    CL            ;Back up cursor
  1603.         JMP    CR_1
  1604. CL_1:
  1605.         MOV    SI,PTR_ARRAY[BX]    ;Start of window
  1606.  
  1607.         DEC    SI            ;Back one char
  1608.         CMP    BYTE PTR [SI],0        ;Past start of string?
  1609.         JE    CR_A            ;Yes, jump
  1610.  
  1611.         MOV    PTR_ARRAY[BX],SI
  1612.         CALL    DISPLAY
  1613.         CLC
  1614.         RET
  1615.  
  1616. CURSOR_LEFT    ENDP
  1617.  
  1618. CURSOR_RIGHT    ENDP
  1619.  
  1620. ;======================================================================
  1621. ;  On entry BX contains 0 = Name or 2 = String.  This proc makes the
  1622. ;  selected string "active."  The cursor position is determined from
  1623. ;  the pointer positions and are retained when jumping up and down.
  1624. ;  Changes:    DH
  1625. ;----------------------------------------------------------------------
  1626. MAKE_ACTIVE    PROC    NEAR
  1627.  
  1628.         MOV    ACTIVE,BX        ;Change active index
  1629.  
  1630.         MOV    CURSOR_COL,7        ;Leftmost column
  1631.  
  1632.         MOV    DH,3            ;Row for name
  1633.         OR    BX,BX            ; if bx=0
  1634.         JZ    MA_1
  1635.         MOV    DH,5            ;Else row for string
  1636. MA_1:        
  1637.         MOV    CURSOR_ROW,DH        ;Save coords
  1638.         RET
  1639.  
  1640. MAKE_ACTIVE    ENDP
  1641.  
  1642. ;======================================================================
  1643. ;  Load the pointers for a new macro set.
  1644. ;  Changes:    BL
  1645. ;  Calls:    GET_POINTER
  1646. ;----------------------------------------------------------------------
  1647. LOAD_POINTERS    PROC    NEAR
  1648.     ASSUME    CS:CSEG, DS:CSEG, ES:CSEG
  1649.  
  1650.         MOV    BL,MACRO_PTR        ;String to look for
  1651.  
  1652.         SHL    BL,1            ; they come in pairs
  1653.  
  1654.         CALL    GET_POINTER        ;Load pointer
  1655.         MOV    NAM_PTR,SI        ;Save offset
  1656.  
  1657.         INC    BL            ;Next string
  1658.         CALL    GET_POINTER        ;Load pointer
  1659.         MOV    STR_PTR,SI        ;Save offset
  1660.  
  1661.         RET
  1662.  
  1663. LOAD_POINTERS    ENDP
  1664.  
  1665. ;======================================================================
  1666. ;  Find the BLth string in the list.  0-based.  Returns SI pointing
  1667. ;  to the start of the string.
  1668. ;  Changes:    AX,BH,SI
  1669. ;----------------------------------------------------------------------
  1670. GET_POINTER    PROC    NEAR
  1671.     ASSUME    CS:CSEG, DS:CSEG, ES:CSEG
  1672.  
  1673.         MOV    SI,OFFSET STRINGS    ;Start scan here
  1674.         XOR    BH,BH            ;String counter
  1675. GP_0:
  1676.         CMP    BH,BL            ;Pointing to right string?
  1677.         JNE    GP_1            ;No, keep scanning
  1678.  
  1679.         RET
  1680. GP_1:
  1681.         LODSB                ;Read char
  1682.         OR    AL,AL            ;Is it 0?
  1683.         JNZ    GP_1
  1684.         INC    BH
  1685.         JMP    GP_0
  1686.  
  1687. GET_POINTER    ENDP
  1688.  
  1689. ;======================================================================
  1690. ;  This procedure will write the active string to the screen from the
  1691. ;  current cursor position forward.  It is called only when a char is
  1692. ;  typed or the window is pushed.
  1693. ;  Changes:    AX,BX,CX,SI
  1694. ;  Calls:    CUR_SET, LOCATE_SI
  1695. ;----------------------------------------------------------------------
  1696. DISPLAY        PROC    NEAR
  1697.     ASSUME    CS:CSEG, DS:CSEG, ES:CSEG
  1698.  
  1699.         CLD                ;String moves forward
  1700.         CALL    CUR_SET            ;Position the cursor
  1701.         CALL    LOCATE_SI        ;Point SI to string
  1702.  
  1703.         MOV    CH,CURSOR_COL
  1704.         MOV    CL,COL_MAX        ;Rightmost column
  1705. DISPLAY_0:
  1706.         LODSB                ;Get character
  1707.         OR    AL,AL            ;Is it end of string?
  1708.         JNZ    DISPLAY_1        ;No, jump
  1709.  
  1710.         DEC    SI            ;Yes, back up
  1711.         MOV    AL,20H            ;Print a space
  1712. DISPLAY_1:
  1713.         CALL    CUR_SET            ;Position the cursor
  1714.  
  1715.         PUSH    CX            ;Save register
  1716.  
  1717.         MOV    AH,0AH            ;Write Char
  1718.         MOV    BH,VPAGE        ;Active page
  1719.         MOV    CX,1
  1720.         INT    10H            ;Thru BIOS
  1721.  
  1722.         POP    CX            ;Restore register
  1723.  
  1724.         INC    CURSOR_COL        ;Change position
  1725.  
  1726.         CMP    CL,CURSOR_COL        ;Is col <= end?
  1727.         JAE    DISPLAY_0        ;Yes, continue
  1728.  
  1729. ;  Past the end of the window - done with display.
  1730.  
  1731.         MOV    CURSOR_COL,CH        ;Return to old spot
  1732.         CALL    CUR_SET            ; do it
  1733.  
  1734.         RET
  1735.  
  1736. DISPLAY        ENDP
  1737.  
  1738. ;======================================================================
  1739. ;  Get a character from the keyboard.  Generate Idle interrupt for
  1740. ;  compatibility with other TSRs.
  1741. ;  Changes:    AX
  1742. ;----------------------------------------------------------------------
  1743. GETKEY        PROC    NEAR
  1744.     ASSUME    CS:CSEG, DS:CSEG, ES:CSEG
  1745.  
  1746. GETKEY_1:
  1747.         INT    28H            ;Generate Dos Idle
  1748.  
  1749.         MOV    AH,1            ;Request KBD status
  1750.         INT    16H            ; Thru BIOS
  1751.         JZ    GETKEY_1        ;None ready
  1752.  
  1753.         XOR    AH,AH            ;Fetch the key
  1754.         INT    16H            ; Thru BIOS
  1755.  
  1756.         RET
  1757.  
  1758. GETKEY        ENDP
  1759.  
  1760. ;======================================================================
  1761. ;  The strings are stored here in ASCIIZ form.
  1762. ;----------------------------------------------------------------------
  1763.         DB    0
  1764. STRINGS        DB    26 DUP(0,0),0        ;They start empty
  1765. STRING_END    EQU    $
  1766.  
  1767. PC        =    $
  1768.  
  1769. PC        =    PC + 256
  1770. STACK_TOP    =    PC
  1771.  
  1772. LASTBYTE    =    PC
  1773.  
  1774. CSEG    ENDS
  1775.     END    ENTPT
  1776.